using RAG.Application.Interfaces;
using RAG.Domain.Entities.App;
using RAG.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; // This using statement is needed for ILogger
using System.Text;

namespace RAG.Application.Services;

/// <summary>
/// 向量服务实现
/// </summary>
public class VectorService : IVectorService
{
    private readonly RagDbContext _db;
    private readonly ILogger<VectorService> _logger;

    public VectorService(RagDbContext db, ILogger<VectorService> logger)
    {
        _db = db;
        _logger = logger;
    }

    private static readonly string DeepSeekEmbeddingApiKey = "sk-882e683548684568a7bdd778ec40c9a7"; // 请替换为你的真实 DeepSeek API Key
    private static readonly string DeepSeekEmbeddingHostUrl = "https://api.deepseek.com/v1/embeddings";

    /// <summary>
    /// 本地降级向量生成（哈希技巧 + L2 归一化，固定维度 1536）。
    /// 仅用于开发/离线环境，避免外部API不可用导致流程中断。
    /// </summary>
    private float[] GenerateLocalEmbedding(string text, int dimension = 1536)
    {
        var vector = new float[dimension];
        if (string.IsNullOrWhiteSpace(text)) return vector;

        // 使用UTF8字节进行哈希分桶
        var bytes = Encoding.UTF8.GetBytes(text);
        for (int i = 0; i < bytes.Length; i++)
        {
            int idx = bytes[i] % dimension;
            vector[idx] += 1.0f;
        }

        // 简单加入二元组频次信息（提升区分度）
        for (int i = 0; i < bytes.Length - 1; i++)
        {
            int combined = (bytes[i] << 8) + bytes[i + 1];
            int idx = combined % dimension;
            if (idx < 0) idx += dimension;
            vector[idx] += 0.5f;
        }

        // L2 归一化
        double sumSquares = 0.0;
        for (int i = 0; i < dimension; i++) sumSquares += vector[i] * vector[i];
        if (sumSquares > 0)
        {
            float norm = (float)Math.Sqrt(sumSquares);
            for (int i = 0; i < dimension; i++) vector[i] /= norm;
        }
        return vector;
    }

    /// <summary>
    /// 调用DeepSeek Embedding API生成向量
    /// </summary>
    public async Task<float[]> GenerateDeepSeekEmbeddingAsync(string text)
    {
        var requestBody = new
        {
            model = "deepseek-embedding",
            input = new[] { text }
        };

        string json = System.Text.Json.JsonSerializer.Serialize(requestBody);

        using (var client = new System.Net.Http.HttpClient())
        {
            client.DefaultRequestHeaders.Clear();
            client.DefaultRequestHeaders.Add("Authorization", $"Bearer {DeepSeekEmbeddingApiKey}");
            var contentObj = new System.Net.Http.StringContent(json, System.Text.Encoding.UTF8, "application/json");
            var response = await client.PostAsync(DeepSeekEmbeddingHostUrl, contentObj);
            var result = await response.Content.ReadAsStringAsync();
            _logger.LogInformation("DeepSeek Embedding API返回：{Result}", result);

            using var doc = System.Text.Json.JsonDocument.Parse(result);
            var root = doc.RootElement;
            if (root.TryGetProperty("data", out var dataArr) && dataArr.GetArrayLength() > 0)
            {
                var embeddingArr = dataArr[0].GetProperty("embedding").EnumerateArray().Select(x => x.GetSingle()).ToArray();
                return embeddingArr;
            }
            throw new Exception("DeepSeek embedding API调用失败或未返回embedding");
        }
    }

    /// <summary>
    /// 通用向量化接口，根据model参数选择DeepSeek或其它embedding
    /// 若外部API不可用，自动降级到本地向量生成，保证流程不中断。
    /// </summary>
    public async Task<float[]> GenerateEmbeddingAsync(string text, string model = null)
    {
        try
        {
            if (!string.IsNullOrEmpty(model) && model.ToLower().Contains("deepseek"))
            {
                return await GenerateDeepSeekEmbeddingAsync(text);
            }
            // 其它embedding模型调用...
            throw new NotImplementedException("请实现其它embedding模型调用逻辑");
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "远程Embedding失败，使用本地降级向量生成");
            return GenerateLocalEmbedding(text);
        }
    }

    /// <summary>
    /// IVectorService接口兼容实现，默认用deepseek-embedding，失败则降级到本地。
    /// </summary>
    public async Task<float[]> GenerateEmbeddingAsync(string text)
    {
        return await GenerateEmbeddingAsync(text, "deepseek-embedding");
    }

    /// <summary>
    /// 批量生成向量
    /// </summary>
    public async Task<List<float[]>> GenerateEmbeddingsAsync(List<string> texts)
    {
        try
        {
            _logger.LogInformation("开始批量生成向量，文本数量: {TextCount}", texts.Count);

            var embeddings = new List<float[]>();
            foreach (var text in texts)
            {
                var embedding = await GenerateEmbeddingAsync(text);
                embeddings.Add(embedding);
            }

            _logger.LogInformation("批量向量生成完成，共生成 {EmbeddingCount} 个向量", embeddings.Count);
            return embeddings;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "批量生成向量失败");
            throw new InvalidOperationException($"批量生成向量失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 计算向量相似度（余弦相似度）
    /// </summary>
    public async Task<double> CalculateSimilarityAsync(float[] vector1, float[] vector2)
    {
        try
        {
            if (vector1.Length != vector2.Length)
            {
                throw new ArgumentException("两个向量的维度必须相同");
            }

            var dotProduct = 0.0;
            var magnitude1 = 0.0;
            var magnitude2 = 0.0;

            for (int i = 0; i < vector1.Length; i++)
            {
                dotProduct += vector1[i] * vector2[i];
                magnitude1 += vector1[i] * vector1[i];
                magnitude2 += vector2[i] * vector2[i];
            }

            magnitude1 = Math.Sqrt(magnitude1);
            magnitude2 = Math.Sqrt(magnitude2);

            if (magnitude1 == 0 || magnitude2 == 0)
            {
                return 0.0;
            }

            var similarity = dotProduct / (magnitude1 * magnitude2);
            return await Task.FromResult(similarity);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "计算向量相似度失败");
            throw new InvalidOperationException($"计算向量相似度失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 向量相似度搜索
    /// </summary>
    public async Task<List<VectorSearchResult>> SearchSimilarVectorsAsync(float[] queryVector, List<VectorData> vectors, int topK = 5)
    {
        try
        {
            _logger.LogInformation("开始向量相似度搜索，查询向量维度: {Dimension}, 候选向量数量: {VectorCount}", 
                queryVector.Length, vectors.Count);

            var results = new List<VectorSearchResult>();

            foreach (var vector in vectors)
            {
                var similarity = await CalculateSimilarityAsync(queryVector, vector.Vector);
                results.Add(new VectorSearchResult
                {
                    ChunkId = vector.ChunkId,
                    Vector = vector.Vector,
                    Similarity = similarity,
                    Content = vector.Content
                });
            }

            // 按相似度排序并返回前topK个结果
            var topResults = results
                .OrderByDescending(r => r.Similarity)
                .Take(topK)
                .ToList();

            _logger.LogInformation("向量相似度搜索完成，返回 {ResultCount} 个结果", topResults.Count);
            return topResults;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "向量相似度搜索失败");
            throw new InvalidOperationException($"向量相似度搜索失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 保存向量到数据库
    /// </summary>
    public async Task<bool> SaveVectorAsync(Guid chunkId, float[] embedding)
    {
        try
        {
            _logger.LogInformation("开始保存向量到数据库，ChunkId: {ChunkId}", chunkId);

            // 检查是否已存在
            var existingVector = await _db.Vectors
                .FirstOrDefaultAsync(v => v.DocumentChunkId == chunkId && !v.IsDeleted);

            if (existingVector != null)
            {
                // 更新现有向量
                existingVector.Embedding = embedding;
                existingVector.UpdatedAt = DateTime.UtcNow;
            }
            else
            {
                // 创建新向量
                var vector = new Vector
                {
                    VectorId = Guid.NewGuid(),
                    DocumentChunkId = chunkId,
                    Embedding = embedding,
                    CreatedAt = DateTime.UtcNow,
                    UpdatedAt = DateTime.UtcNow
                };

                _db.Vectors.Add(vector);
            }

            await _db.SaveChangesAsync();

            _logger.LogInformation("向量保存成功，ChunkId: {ChunkId}", chunkId);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "保存向量失败，ChunkId: {ChunkId}", chunkId);
            return false;
        }
    }

    /// <summary>
    /// 从数据库获取向量
    /// </summary>
    public async Task<float[]?> GetVectorAsync(Guid chunkId)
    {
        try
        {
            var vector = await _db.Vectors
                .FirstOrDefaultAsync(v => v.DocumentChunkId == chunkId && !v.IsDeleted);

            return vector?.Embedding;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取向量失败，ChunkId: {ChunkId}", chunkId);
            return null;
        }
    }

    /// <summary>
    /// 删除向量（软删除）
    /// </summary>
    public async Task<bool> DeleteVectorAsync(Guid chunkId)
    {
        try
        {
            var vector = await _db.Vectors
                .FirstOrDefaultAsync(v => v.DocumentChunkId == chunkId && !v.IsDeleted);

            if (vector == null)
            {
                return false;
            }

            vector.IsDeleted = true;
            vector.UpdatedAt = DateTime.UtcNow;
            await _db.SaveChangesAsync();
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "删除向量失败，ChunkId: {ChunkId}", chunkId);
            return false;
        }
    }
}
